{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Tutorial 07: Networks from Custom Templates\n",
    "\n",
    "In the previous tutorial, we discussed how OpenStreetMap files can be simulated in Flow. These networks, however, may at time be imperfect, as we can see in the toll section of the Bay Bridge (see the figure below). The simulators SUMO and Aimsun both possess methods for augmenting the network after they have been imported, and store the changes in their own versions of the initial template (whether it was generated via a custom network class or a network imported from OpenStreetMap). In order to utilize these newly generated networks, we demonstrate in this tutorial how simulator-generated template files can be imported when running a simulation in Flow. \n",
    "\n",
    "<img src=\"img/osm_to_template.png\">\n",
    "<center> **Figure 1**: Example benefit of converting OpenStreetMap to a custom template </center>\n",
    "\n",
    "The remainder of the tutorial is organized as follows. In section 1, we begin by importing the classic set of parameters. In section 2, we introduce the template files that are used as examples for importing the template files. In section 3, we present how custom SUMO network templates, i.e. the generated .net.xml files, can be modified and simulated in Flow for the purposed of improving network features. Finally, in section 4, we demonstrate how custom Aimsun network files can be simulated in Flow.\n",
    "\n",
    "## 1. Importing Modules\n",
    "\n",
    "Before we begin, let us import all relevant Flow parameters as we have done for previous tutorials. If you are unfamiliar with these parameters, you are encouraged to review tutorial 1."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# the TestEnv environment is used to simply simulate the network\n",
    "from flow.envs import TestEnv\n",
    "\n",
    "# the Experiment class is used for running simulations\n",
    "from flow.core.experiment import Experiment\n",
    "\n",
    "# the base network class\n",
    "from flow.networks import Network\n",
    "\n",
    "# all other imports are standard\n",
    "from flow.core.params import VehicleParams\n",
    "from flow.core.params import NetParams\n",
    "from flow.core.params import InitialConfig\n",
    "from flow.core.params import EnvParams\n",
    "\n",
    "# create some default parameters parameters\n",
    "env_params = EnvParams()\n",
    "initial_config = InitialConfig()\n",
    "vehicles = VehicleParams()\n",
    "vehicles.add('human', num_vehicles=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Example Network\n",
    "\n",
    "In this tutorial, we use the [Luxembourg SUMO Traffic (LuST) Network](https://github.com/lcodeca/LuSTScenario) as an example use case. This example consists of a well-calibrated model of vehicles in Luxembourg. A representation of the simulation can be seen in the figure below.\n",
    "\n",
    "<img src=\"img/LuST_network.png\" width=\"500\">\n",
    "<center><b>Figure 2</b>: Simulation of the LuST network </center>\n",
    "\n",
    "Before, continuing with this tutorial, please begin by cloning the LuST scenario repository by running the following command.\n",
    "\n",
    "    git clone https://github.com/lcodeca/LuSTScenario.git\n",
    "\n",
    "Once you have cloned the repository, please modify the code snippet below to match correct location of the repository's main directory."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "LuST_dir = \"/path/to/LuSTScenario\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Sumo Network Files\n",
    "\n",
    "Sumo generates several network and simulation-specifc template files prior to starting a simulation. This procedure when creating custom networks and networks from OpenStreetMap is covered by the network class. Three of these files (\\*.net.xml, \\*.rou.xml, and vtype.add.xml) can be imported once again via the network class to recreate a previously designed network.\n",
    "\n",
    "We start by creating the simulation parameters:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from flow.core.params import SumoParams\n",
    "\n",
    "sim_params = SumoParams(render=True, sim_step=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.1 Importing Network (\\*.net.xml) Files\n",
    "\n",
    "The \\*.net.xml file covers the network geometry within a simulation, and can be imported independently of the SUMO route file (see section 1.2). This can be done through the `template` parameter within `NetParams` as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "\n",
    "net_params = NetParams(\n",
    "    template=os.path.join(LuST_dir, \"scenario/lust.net.xml\"),\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This network alone, similar to the OpenStreetMap file, does not cover the placement of vehicles or the routes vehicles can traverse. These, however, can be defined a they were in the previous tutorial for importing networks from OpenStreetMap. For the LuST network, this looks something similar to the following code snippet (note that the specific edges were not spoken for any specific reason)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# specify the edges vehicles can originate on\n",
    "initial_config = InitialConfig(\n",
    "    edges_distribution=[\"-32410#3\"]\n",
    ")\n",
    "\n",
    "\n",
    "# specify the routes for vehicles in the network\n",
    "class TemplateNetwork(Network):\n",
    "\n",
    "    def specify_routes(self, net_params):\n",
    "        return {\"-32410#3\": [\"-32410#3\"]}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The simulation can then be executed as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "flow_params = dict(\n",
    "    exp_tag='template',\n",
    "    env_name=TestEnv,\n",
    "    network=TemplateNetwork,\n",
    "    simulator='traci',\n",
    "    sim=sim_params,\n",
    "    env=env_params,\n",
    "    net=net_params,\n",
    "    veh=vehicles,\n",
    "    initial=initial_config,\n",
    ")\n",
    "\n",
    "# number of time steps\n",
    "flow_params['env'].horizon = 1000\n",
    "exp = Experiment(flow_params)\n",
    "\n",
    "# run the sumo simulation\n",
    "_ = exp.run(1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.2 Importing Additional Files\n",
    "\n",
    "Sumo templates will at times contain files other than the network templates that can be used to specify the positions, speeds, and properties of vehicles at the start of a simulation, as well as the departure times of vehicles while the network is running and the routes that all these vehicles are meant to traverse. All these files can also be imported under the `template` attribute in order to recreate the simulation in it's entirety.\n",
    "\n",
    "When incorporating files other that the net.xml file to the simulation, the template attribute is treated as a dictionary instead, with a different element for each of the additional files that are meant to be imported. Starting with the net.xml file, it is added to the template attribute as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "new_net_params = NetParams(\n",
    "    template={\n",
    "        # network geometry features\n",
    "        \"net\": os.path.join(LuST_dir, \"scenario/lust.net.xml\")\n",
    "    }\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 3.2.1 Vehicle Type (vtype.add.xml)\n",
    "\n",
    "The vehicle types file describing the properties of different vehicle types in the network. These include parameters such as the max acceleration and comfortable deceleration of drivers. This file can be imported via the \"vtype\" attribute in template.\n",
    "\n",
    "Note that, when vehicle information is being imported from a template file, the `VehicleParams` object does not need be modified, unless you would like additionally vehicles to enter the network as well."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "new_net_params = NetParams(\n",
    "    template={\n",
    "        # network geometry features\n",
    "        \"net\": os.path.join(LuST_dir, \"scenario/lust.net.xml\"),\n",
    "        # features associated with the properties of drivers\n",
    "        \"vtype\": os.path.join(LuST_dir, \"scenario/vtype.add.xml\")\n",
    "    }\n",
    ")\n",
    "\n",
    "# we no longer need to specify anything in VehicleParams\n",
    "new_vehicles = VehicleParams()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 3.2.2 Route (\\*.rou.xml)\n",
    "\n",
    "Next, the routes can be imported from the \\*.rou.xml files that are generated by SUMO. These files help define which cars enter the network at which point in time, whether it be at the beginning of a simulation or some time during it run. The route files are passed to the \"rou\" key in the templates attribute. Moreover, since the vehicle routes can be spread over multiple files, the \"rou\" key that a *list* of string filenames."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "new_net_params = NetParams(\n",
    "    template={\n",
    "        # network geometry features\n",
    "        \"net\": os.path.join(LuST_dir, \"scenario/lust.net.xml\"),\n",
    "        # features associated with the properties of drivers\n",
    "        \"vtype\": os.path.join(LuST_dir, \"scenario/vtypes.add.xml\"),\n",
    "        # features associated with the routes vehicles take\n",
    "        \"rou\": [os.path.join(LuST_dir, \"scenario/DUARoutes/local.0.rou.xml\"),\n",
    "                os.path.join(LuST_dir, \"scenario/DUARoutes/local.1.rou.xml\"),\n",
    "                os.path.join(LuST_dir, \"scenario/DUARoutes/local.2.rou.xml\")]\n",
    "    }\n",
    ")\n",
    "\n",
    "# we no longer need to specify anything in VehicleParams\n",
    "new_vehicles = VehicleParams()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 3.2.3 Running the Modified Simulation\n",
    "\n",
    "Finally, the fully imported simulation can be run as follows. \n",
    "\n",
    "**Warning**: the network takes time to initialize while the departure positions and times and vehicles are specified."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "flow_params = dict(\n",
    "    exp_tag='template',\n",
    "    env_name=TestEnv,\n",
    "    network=Network,\n",
    "    simulator='traci',\n",
    "    sim=sim_params,\n",
    "    env=env_params,\n",
    "    net=new_net_params,\n",
    "    veh=new_vehicles,\n",
    "    initial=initial_config,\n",
    ")\n",
    "\n",
    "# number of time steps\n",
    "flow_params['env'].horizon = 100000\n",
    "exp = Experiment(flow_params)\n",
    "\n",
    "# run the sumo simulation\n",
    "_ = exp.run(1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. Aimsun Network Files\n",
    "\n",
    "Flow can run templates that have been created in Aimsun and saved into an \\*.ang file. Although it is possible to have control over the network, for instance add vehicles and monitor them directly from Flow, this tutorial only covers how to run the network.\n",
    "\n",
    "We will use the template located at `tutorials/networks/test_template.ang`, which looks like this:\n",
    "\n",
    "<img src=\"img/test_template.png\">\n",
    "<center><b>Figure 2</b>: Simulation of <code>test_template.ang</code> in Aimsun</center>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It contains two input and three output centroids that define the centroid configuration `Centroid Configuration 910`. The inflows are defined by two OD matrices, one for the type `Car` (in blue), the other for the type `rl` (in red). Note that there is no learning in this tutorial so the two types both act as regular cars. The two OD matrices form the traffic demand `Traffic Demand 925` that is used by the network `Dynamic Scenario 927`. Finally, the experiment `Micro SRC Experiment 928` and the replication `Replication 930` are created, and we will run this replication in the following."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, we create the Aimsun-specific simulation parameters:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "from flow.core.params import AimsunParams\n",
    "\n",
    "sim_params = AimsunParams(\n",
    "    sim_step=0.1,\n",
    "    render=True,\n",
    "    emission_path='data',\n",
    "    replication_name=\"Replication 930\",\n",
    "    centroid_config_name=\"Centroid Configuration 910\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As you can see, we need to specify the name of the replication we want to run as well as the centroid configuration that is to be used. There is an other optional parameter, `subnetwork_name`, that can be specified if only part of the network should be simulated. Please refer to the documentation for more information. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The template can then be imported as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import flow.config as config\n",
    "\n",
    "net_params = NetParams(\n",
    "    template=os.path.join(config.PROJECT_PATH,\n",
    "                          \"tutorials/networks/test_template.ang\")\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, we can run the simulation by specifying `'aimsun'` as the simulator to be used:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "flow_params = dict(\n",
    "    exp_tag='template',\n",
    "    env_name=TestEnv,\n",
    "    network=Network,\n",
    "    simulator='aimsun',\n",
    "    sim=sim_params,\n",
    "    env=env_params,\n",
    "    net=net_params,\n",
    "    veh=vehicles,\n",
    "    initial=initial_config,\n",
    ")\n",
    "\n",
    "# number of time steps\n",
    "flow_params['env'].horizon = 1000\n",
    "exp = Experiment(flow_params)\n",
    "\n",
    "# run the sumo simulation\n",
    "_ = exp.run(1)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
